In This Topic
The Grid Surface series displays a surface with user-defined elevation values for each data point and with X and Y coordinates which form a rectangular grid. Grid Surface series are represented by the NGridSurfaceSeries type. The following figure displays a typical grid surface chart:
Creating a Grid Surface Series
To create a grid surface you have to create an instance of the NGridSurfaceSeries type and add it to the series collection of the chart. Surface series can be displayed only in 3D mode, so it is required to enable 3D for the chart hosting the series. The following code shows how to create a new grid surface series and add it to the chart:
C# |
Copy Code
|
// setup chart
NCartesianChart chart = (NCartesianChart)chartView.Surface.Charts[0];
chart.Enable3D = true;
// set aspect 1:1:1
chart.ModelWidth = 50;
chart.ModelHeight = 50;
chart.ModelDepth = 50;
// set projection
chart.Projection.SetPredefinedProjection(ENPredefinedProjection.PerspectiveTilted);
// create a surface series
NGridSurfaceSeries surface = new NGridSurfaceSeries();
// add the series to the chart series collection
chart.Series.Add(surface);
|
Grid Surface Data
The surface elevation data is contained in an object of type NGridSurfaceData object, which is accessible through the Data property of the NGridSurfaceSeries class. The data is stored as a two-dimensional array of data points, where each data point has one double value (the elevation value), and optionally a color value. The size of the surface grid is controlled with the help of the SetGridSize method of the NGridSurfaceData object. It accepts two integer parameters - sizeX (defines the width of the surface) and sizeZ (defines the depth of the surface). The SetValue method sets a value at a specified X and Z index. The passed value will be converted to a float value internally for faster processing by the GPU. If you need to specify an invalid data point at some position you can use DBNull.Value or float.NaN. The following example creates a grid surface series with 9 data points (4 segments) and adds some data to it.
C# |
Copy Code
|
// obtain a reference to the Cartesian chart that is created by default
NCartesianChart chart = (NCartesianChart)chartView.Surface.Charts[0];
chart.Enable3D = true;
// set aspect 1:1:1
chart.ModelWidth = 50;
chart.ModelHeight = 50;
chart.ModelDepth = 50;
// set projection
chart.Projection.SetPredefinedProjection(ENPredefinedProjection.PerspectiveTilted);
// create a surface series
NGridSurfaceSeries surface = new NGridSurfaceSeries();
chart.Series.Add(surface);
surface.FrameMode = ENSurfaceFrameMode.Mesh;
surface.Name = "Grid Surface";
// add some data
surface.Data.SetGridSize(3, 3);
surface.Data.SetValue(0, 0, 0.8);
surface.Data.SetValue(1, 0, 0.0);
surface.Data.SetValue(2, 0, 0.0);
surface.Data.SetValue(0, 1, 1.0);
surface.Data.SetValue(1, 1, 1.2);
surface.Data.SetValue(2, 1, 0.5);
surface.Data.SetValue(0, 2, 4.0);
surface.Data.SetValue(1, 2, 2.0);
surface.Data.SetValue(2, 2, 1.3);
|
The following figure displays the generated surface as well as the order of X and Z indices in the surface grid:
You can get the value at a specific X/Z index in the grid using the GetValue method of the NGridSurfaceData object. It returns a float value which in the case of an invalid data point has the value of float.NaN. The GridSizeX and GridSizeZ properties can be used to retrieve the current X and Z size of the surface data respectively.
Grid Surface With Custom Colors
When the grid surface FillMode is set to ENSurfaceFillMode.CustomColors or FrameColorMode is set to ENSurfaceFrameColorMode.CustomColors the surface will display the filling/frame with custom colors per vertex. In this case, you also need to pass a color value for each vertex. This is achieved by using the SetColor method of the grid surface data object - for example:
C# |
Copy Code
|
surface.Data.UseColors = true;
surface.Data.SetColor(0, 0, Color.Red);
|
Passing Large Amounts of Data
When you have to feed large amounts of data to the grid surface series using the SetValue and SetColor methods will not be very efficient because it results in a function call for each value or color that is set. In such cases, you can consider adding data using unsafe code in which case you directly modify the surface data object in memory. The following code shows how to achieve this:
C# |
Copy Code
|
// create a surface series
NGridSurfaceSeries gridSurface = new NGridSurfaceSeries();
// add the series to the chart series collection
chart.Series.Add(gridSurface);
gridSurface.Data.HasColor = true;
gridSurface.Data.SetGridSize(10, 10);
unsafe
{
fixed (byte* pData = &gridSurface.Data.Data[0])
{
int dataItemSize = gridSurface.Data.DataItemSize;
float* gridValues = (float*)pData;
uint* gridColors = (uint*)(pData + gridSurface.Data.ColorOffset);
gridValues[0 * dataItemSize] = 10; // same as calling SetValue(0, 0, 10);
gridValues[1 * dataItemSize] = 20; // same as calling SetValue(1, 0, 20);
gridValues[10 * dataItemSize] = 20; // same as calling SetValue(0, 1, 20);
gridColors[0 * dataItemSize] = 0xFF0000; // same as calling SetColor(0, 0, Color.Blue);
gridColors[1 * dataItemSize] = 0x00FF00; // same as calling SetColor(1, 0, Color.Green);
gridColors[10 * dataItemSize] = 0x0000FF; // same as calling SetColor(0, 1, Color.Red);
}
}
// notify the surface that data has changed
gridSurface.Data.OnDataChanged();
|
See Also